package com.hp.btc.controller;

import java.io.BufferedWriter;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.hp.btc.bean.BeanCampaign;
import com.hp.btc.bean.BeanDescriptionVDN;
import com.hp.btc.bean.BeanServiceVDN;
import com.hp.btc.bean.BeanVDN;
import com.hp.btc.util.MessageHelper;
import com.services.ws.auditoria.RegistroAuditoriaManager;
import com.services.ws.auditoria.model.AccesoResponse;
import com.services.ws.auditoria.model.RegistroRequest;


@Controller
@RequestMapping("/dashboard")
@SessionAttributes(value="descriptionBean")
public class DashboardController extends BaseController{
	
	private static final Logger logger = LoggerFactory.getLogger(DashboardController.class);
	
	@Autowired
	private RegistroAuditoriaManager registroAuditoriaManager;
	
	private String maintenanceProcess = "";
	
	@RequestMapping("/")
	public ModelAndView showPageInit(SessionStatus status){
		logger.debug(" ******* start page *****");
		status.setComplete();
		reloadFiles();
		maintenanceProcess="";
		ModelAndView mav = new ModelAndView("dashboard");
		mav.addObject("descriptionVDN", desService.getAllDescriptionVdns());
		return mav;
	}
	
	@RequestMapping(value="/allVdns", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
	@ResponseStatus(HttpStatus.OK)
	public @ResponseBody List<BeanVDN> showVdns(){
		logger.debug("all lista vdn");
		return vdnService.getAllVdns();
	}
	
	@RequestMapping(value="/allDescriptionsVdn", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
	public @ResponseBody List<BeanDescriptionVDN> showDescriptionVdn(){
		logger.debug("all description vdn");
		return desService.getAllDescriptionVdns();
	}
	
	@RequestMapping(value="/descriptionvdn/{id}/services", method=RequestMethod.GET)
	public String getDescription(@PathVariable("id") String id, Model model){
		try{
			logger.debug("obtenemos la descipcion por id {}", id);
			BeanDescriptionVDN descriptionVDN = desService.getDescriptionById(id);
			String vdnConcat = "";
			String vdnhourConcat = "";
			for (BeanServiceVDN beanServiceVDN : descriptionVDN.getOptionService()) {
				vdnConcat += beanServiceVDN.getBeanVDN().getValue().concat(",");
				if(beanServiceVDN.getBeanVDNOutHour()!=null)
					vdnhourConcat += beanServiceVDN.getBeanVDNOutHour().getValue().concat(",");
			}
			if(StringUtils.hasLength(vdnhourConcat))
				vdnhourConcat = vdnhourConcat.substring(0, vdnhourConcat.length()-1);
			
			logger.info("*****  vdn {}   and vdnhour {}",vdnConcat, vdnhourConcat);
			model.addAttribute("descriptionBean", descriptionVDN);
			model.addAttribute("listusevdn", vdnConcat.substring(0, vdnConcat.length()-1));
			model.addAttribute("listusevdnhour", vdnhourConcat);
			model.addAttribute("process", maintenanceProcess);
		}catch(Exception ex){
			logger.error("***ERROR***", ex);
		}
		return "fragment/detailService :: descriptionOfBeans";
	}
	
	@RequestMapping(value="/refreshselect/{isMsgError}")
	public String refreshOptions(@PathVariable("isMsgError") String value, Model model){
		logger.info("update to list of selectors {}", value);
		boolean isMsgError = false;
		
		if(StringUtils.hasText(value) && (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")))
			isMsgError = Boolean.parseBoolean(value);
		
		logger.info("Message error is: {}",isMsgError);
		
		if(!model.containsAttribute("descriptionBean"))
			return null;
		
		Map<String, Object> modelMap = model.asMap();
		BeanDescriptionVDN beanLocal = (BeanDescriptionVDN)modelMap.get("descriptionBean");
		beanLocal.setHaveMessageError(isMsgError);
		model.addAttribute(beanLocal);
		logger.info("Local bean {}", beanLocal);
		return "fragment/detailService :: refreshSelect";
	}
	
	@RequestMapping(value="/campaign/{name}", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
	public @ResponseBody List<BeanCampaign> getShortCodeForCampaign(@PathVariable("name")String nameCampaign, Model model){
		List<BeanCampaign> campaigns = balanceTranfer.getListCampaigns();
		List<BeanCampaign> tmpCampaigns = new LinkedList<BeanCampaign>();
		for (BeanCampaign campaign : campaigns) {
			if(campaign.getName().equalsIgnoreCase(nameCampaign))
				tmpCampaigns.add(campaign);
		}
		//model.addAttribute("shortcodes", tmpCampaigns);
		return tmpCampaigns;
		//model.addAttribute("descriptionVDN", desService.getDescriptionVdnsForName(nameCampaign));
//		return "dashboard :: shortCodes";
	}
	
	@RequestMapping(value="/showVDNS/{name}/{shortcode}", method=RequestMethod.GET)
	public String showValuesContent(@PathVariable("name")String nameCampaign, @PathVariable("shortcode")String shortcode, Model model){
		logger.info("nameCampaign {} and shortCode {}", nameCampaign, shortcode);
		List<BeanDescriptionVDN> tmpDescriptionVDN = new ArrayList<BeanDescriptionVDN>();
		if(StringUtils.hasText(nameCampaign)){
			reloadFiles();
			logger.info("nameCampaign {} and shortCode {}", nameCampaign, shortcode);
			if(!StringUtils.hasText(shortcode) || shortcode.equalsIgnoreCase("0")){
				tmpDescriptionVDN = desService.getDescriptionVdnsForName(nameCampaign);
			}else{
				tmpDescriptionVDN = desService.getDescriptionVdnsForNameAndShortCode(nameCampaign, shortcode);
			}
		}
//		model.addAttribute("nameCampaign", nameCampaign);
		model.addAttribute("shortcode", shortcode);
		//model.addAttribute("descriptionVDN", desService.getAllDescriptionVdns());
		model.addAttribute("descriptionVDN", tmpDescriptionVDN);
		return "dashboard :: refreshTable";
	}
	
	
	@RequestMapping(value="/servicevdn/{idService}/edit", method=RequestMethod.GET)
	public String getService(@PathVariable("idService") String idService, Model model, 
			@ModelAttribute(value="descriptionBean") BeanDescriptionVDN descriptionBean){
		logger.info("getService by id {}", idService);
		for(BeanServiceVDN bean :descriptionBean.getOptionService()){
			if(bean.getId().equalsIgnoreCase(idService)){
				model.addAttribute("servicevdnForm", bean);
				model.addAttribute("excludevdn", bean.getBeanVDN().getValue());
				if(bean.getBeanVDNOutHour()!=null)
					model.addAttribute("excludevdnhour", bean.getBeanVDNOutHour().getValue());
				logger.info("Found service {}", bean);
			}
		}
		return "fragment/modal_service :: maintainService";
	}
	
	@RequestMapping(value="/servicevdn/new", method=RequestMethod.GET)
	public String newService(Model model){
		model.addAttribute("servicevdnForm",new BeanServiceVDN());
		return "fragment/modal_service :: maintainService";
	}
	
	@RequestMapping(value="/servicevdn/save/edit", method={RequestMethod.PUT, RequestMethod.POST})
	public String processUpdateServiceIntoDescription(@ModelAttribute BeanServiceVDN servicevdn,
			@ModelAttribute(value="descriptionBean") BeanDescriptionVDN beanDescription, @RequestParam(value="modalProcess") String process){
		logger.debug("**servicevdn=> {}", servicevdn);
		servicevdn.setBeanVDN(balanceTranfer.findVDNbyValue(servicevdn.getVdn()));
		servicevdn.setBeanVDNOutHour(balanceTranfer.findVDNbyValue(servicevdn.getVdnOutHour()));
		servicevdn.setSendTextToAudit(util.formatStringServiceHour(servicevdn.getServiceHour()));
		desService.updateServiceInDescription(beanDescription, servicevdn);
		maintenanceProcess = process;
		
		return "redirect:/dashboard/descriptionvdn/"+beanDescription.getIdDescription()+"/services";
	}
	
	@RequestMapping(value="/servicevdn/save/edit/vality", method=RequestMethod.POST)
	public String processUpdateServiceIntoValidityDescription(@ModelAttribute(value="descriptionBean") BeanDescriptionVDN descriptionBean, 
			@RequestParam(value="modalProcess") String process, @RequestParam(value="valityUpdate") String valityUpdate, @RequestParam(value="idService") String idService){
		logger.debug("******processUpdateServiceIntoValidityDescription*****");
		logger.debug("**descriptionBean=> {}", descriptionBean);
		List<BeanServiceVDN> optionServices = descriptionBean.getOptionService();
		BeanServiceVDN servicevdnTmp = new BeanServiceVDN();
		for(BeanServiceVDN servicevdn : optionServices){
			if(servicevdn.getId().equalsIgnoreCase(idService)){
				servicevdn.setStatus(valityUpdate);
				servicevdnTmp = servicevdn;
				break;
			}
		}
		desService.updateServiceInDescription(descriptionBean, servicevdnTmp);
		maintenanceProcess = process;
		return "redirect:/dashboard/descriptionvdn/"+descriptionBean.getIdDescription()+"/services";
	}
	
	@RequestMapping(value="/servicevdn/save/new", method={RequestMethod.PUT, RequestMethod.POST})
	public String processSaveServiceIntoDescription(@ModelAttribute BeanServiceVDN servicevdn,
			@ModelAttribute(value="descriptionBean") BeanDescriptionVDN beanDescription, @RequestParam(value="modalProcess") String process){
		logger.debug("servicevdn==> {}", servicevdn);
		
		servicevdn.setBeanVDN(balanceTranfer.findVDNbyValue(servicevdn.getVdn()));
		servicevdn.setBeanVDNOutHour(balanceTranfer.findVDNbyValue(servicevdn.getVdnOutHour()));
		servicevdn.setSendTextToAudit(util.formatStringServiceHour(servicevdn.getServiceHour()));
		desService.addServiceInDescriptionList(beanDescription.getIdDescription(), servicevdn);
		maintenanceProcess = process;
		System.out.println("## Process="+process);
		return "redirect:/dashboard/descriptionvdn/"+beanDescription.getIdDescription()+"/services";
	}
	
	@RequestMapping(value="/save", method=RequestMethod.POST)
	public String processSaveDescription(@ModelAttribute BeanDescriptionVDN descriptionVdn, 
			@ModelAttribute(value="descriptionBean") BeanDescriptionVDN beanDescription,
			HttpSession session, HttpServletRequest request, RedirectAttributes ra, @RequestParam(value="process") String process){
		logger.debug("**processSaveDescription {}",descriptionVdn);
		AccesoResponse access = (AccesoResponse)session.getAttribute("Access");
		descriptionVdn.setOption(beanDescription.getOption());
		
		List<BeanDescriptionVDN> descriptions = desService.getAllDescriptionVdns();
		List<BeanDescriptionVDN> descriptionsTemp = new ArrayList<BeanDescriptionVDN>();
		for (BeanDescriptionVDN beanDescriptionVDN : descriptions) {
			if(beanDescriptionVDN.getIdDescription().equalsIgnoreCase(descriptionVdn.getIdDescription())){
				beanDescriptionVDN.setLastDateModified(new Date());
				beanDescriptionVDN.setLastUserModified(access.getNombre()+" "+access.getPaterno());
				beanDescriptionVDN.setOptionService(beanDescription.getOptionService());
				logger.info("1)beanDescription {}",beanDescriptionVDN);
			}
			descriptionsTemp.add(beanDescriptionVDN);
		}
		balanceTranfer.setService_description(descriptionsTemp);
		util.setIpClient(request.getLocalAddr());

		util.writeFiletoPath(balanceTranfer);
		path = util.getRootFileTmpJson();
		
		logger.debug("** {}",ReflectionToStringBuilder.toString(access));
		
		String username = (String)session.getAttribute("username");
		String btnProcess = "";
		String messageText="";
		if(process.equalsIgnoreCase("insert")){
			messageText="description.vdn.create.success";
			btnProcess = btnSave;
		}if(process.equalsIgnoreCase("update")){
			messageText="description.vdn.update.success";
			btnProcess = btnUpdate;
		}
		sentAuditServices(beanDescription.getOptionService(), request, username, btnProcess);
		util.syncronitedFiletoServers(path);
		MessageHelper.addInfoAttribute(ra, messageText, beanDescription.getCampaign());
		return "redirect:/dashboard/";
	}
	
	private void sentAuditServices(List<BeanServiceVDN> serviceVDN, HttpServletRequest request, String username, String processBtn){
		for (BeanServiceVDN beanServiceVDN : serviceVDN) {
			if(StringUtils.hasText(beanServiceVDN.getSendTextToAudit()))
				sendToAuditWS(request, username, processBtn, beanServiceVDN.getSendTextToAudit());
		}
	}
	
	
	 enum OutputFormat {csv, xml}
	
	@RequestMapping("/export/{id}/services")
    public void exportServicesAsCsv(@RequestParam(required = false, defaultValue = "csv") OutputFormat format, 
    		@PathVariable("id") String id,HttpServletResponse response, HttpSession session, HttpServletRequest request) throws IOException {
		logger.info("exportServicesAsCsv to export services");
		BeanDescriptionVDN beanDescription = desService.getDescriptionById(id);
        List<BeanServiceVDN> serviecs = beanDescription.getOptionService();
        
        String username = (String)session.getAttribute("username");
        sendToAuditWS(request, username, btnExport, beanDescription.toSendAudit());
        
        BufferedWriter writer = new BufferedWriter(response.getWriter());
        String file = "";
        if (format.equals(OutputFormat.csv)) {
            writeServicesAsCsv(serviecs, writer);
            file = "export.csv";
        }        
        setHeader(response, file);
        writer.flush();
    }
	
	private void sendToAuditWS(HttpServletRequest request, String username, String transaction, String text){
		//String transactionFormaterDate = util.getFormatterDateuntilMilliseconds();
		String ipServer = request.getLocalAddr();
		String nameServer = request.getLocalName();
		String ipClient = request.getRemoteAddr();
		String nameClient = request.getRemoteHost();
		String hostname = null;
		
		logger.info("ipServer="+ipServer+"  nameServer="+nameServer+"  ipclient="+ipClient+"  nameClient="+nameClient);
		try {
			hostname = InetAddress.getByName(ipClient).getHostName();
			nameClient = hostname;
		} catch (UnknownHostException e) {
			logger.error("{}",e);
		}
		
		logger.info("*##* hostname {}",hostname);
		
		RegistroRequest registroRequest = null;
		try {
			registroRequest = new RegistroRequest();
			registroRequest.setTransaccion(transaction);
			registroRequest.setServicio(serviceAudit);
			registroRequest.setIpCliente(ipClient);
			registroRequest.setNombreCliente(nameClient);
			registroRequest.setIpServidor(ipServer);
			registroRequest.setNombreServidor(nameServer);
			registroRequest.setCuentaUsuario(username);
			registroRequest.setTexto(text);
			registroRequest.setTelefono("");
			registroRequest.setMonto("");
			
			logger.info(ReflectionToStringBuilder.toString(registroRequest));
			
			registroAuditoriaManager.registroAuditoria(registroRequest, Integer.parseInt(timeout));
		} catch (Exception exception) {
			logger.error("", exception);
		}
	}
	
	private void writeServicesAsCsv(List<BeanServiceVDN> services, BufferedWriter writer) throws IOException {
		writer.write("Codigo;Vigencia;Dia/Hora;VDN;Site;VDN Out Hour;Site;Ponderacion");
		writer.newLine();
        for (BeanServiceVDN bean : services) {
            writer.write(String.format("%s;%s;%s;%s;%s;%s;%s;%d",
                    bean.getId(), bean.getStatus(), bean.getServiceHour(), 
                    bean.getBeanVDN()!=null?bean.getBeanVDN().getValue():"", bean.getBeanVDN()!=null?bean.getBeanVDN().getSite():"", 
                    bean.getBeanVDNOutHour()!=null?bean.getBeanVDNOutHour().getValue():"", bean.getBeanVDNOutHour()!=null?bean.getBeanVDNOutHour().getSite():"", 
                    bean.getRate())
            );
            writer.newLine();
        }
    }
	
	private void setHeader(HttpServletResponse response, String file) {
        response.setHeader("Content-Disposition", "attachment; filename=\"" + file + "\"");
    }

}
	